package com.molichuxing.services.infrastructure.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.DateUtil;
import com.molichuxing.framework.utils.ObjectCastUtil;
import com.molichuxing.services.exception.OrderExceptionCodeEnum;
import com.molichuxing.services.infrastructure.bean.OrderScheduleBean;
import com.molichuxing.services.infrastructure.convertor.Convert;
import com.molichuxing.services.infrastructure.dao.OrderScheduleMapper;
import com.molichuxing.services.infrastructure.dto.request.create.OrderScheduleDealerCreateDto;
import com.molichuxing.services.infrastructure.dto.request.create.OrderScheduleUserCreateDto;
import com.molichuxing.services.infrastructure.dto.request.modify.OrderPayModifyDto;
import com.molichuxing.services.infrastructure.dto.request.modify.OrderSchedulePayableDateModifyDto;
import com.molichuxing.services.infrastructure.dto.request.modify.OrderScheduleRepaymentModifyDto;
import com.molichuxing.services.infrastructure.dto.response.*;
import com.molichuxing.services.infrastructure.service.OrderScheduleService;
import com.molichuxing.services.property.OrderScheduleStatusEnum;
import com.molichuxing.services.property.OrderTypeEnum;
import com.molichuxing.services.utils.OrderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单排期基础服务
 *
 * @author zoumingyu
 * @date 2019年8月14日
 */
@Service("orderScheduleService")
public class OrderScheduleServiceImpl implements OrderScheduleService {
    private static final Logger logger = LoggerFactory.getLogger(OrderScheduleServiceImpl.class);

    @Autowired
    private OrderScheduleMapper orderScheduleMapper;

    /**
     * id查询订单排期信息
     *
     * @param id 排期id
     * @return
     */
    @Override
    public OrderScheduleDto getOrderSchedule(Integer id) {
        return Convert.toOrderScheduleBeanDto(orderScheduleMapper.getById(id));
    }

    /**
     * 查询订单排期信息
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    public List<OrderScheduleDto> getOrderSchedule(Long orderCode) {
        return this.getOrderSchedule(orderCode, null);
    }

    /**
     * 查询订单排期信息
     *
     * @param orderCode           订单号
     * @param orderScheduleStatus 订单排期状态枚举
     * @return
     */
    @Override
    public List<OrderScheduleDto> getOrderSchedule(Long orderCode, OrderScheduleStatusEnum orderScheduleStatus) {
        return Convert.toOrderScheduleBeanDto(orderScheduleMapper.getList(orderCode,
                orderScheduleStatus == null ? null : orderScheduleStatus.getValue()));
    }

    /**
     * 查询专属里程订单本期排期
     *
     * @param params orderCode 订单号-long
     *               userIds   用户id(查询C端用户订单排期)-list
     * @return
     * @throws Exception
     */
    @Override
    public Paged<OrderScheduleCurrentPeriodDto> getExclusivelOrderCurrentPeriod(Map<String, Object> params, int pageNum,
                                                                                int pageSize) throws Exception {
        return getCurrentPeriod(params, OrderTypeEnum.EXCLUSIVEL, pageNum, pageSize);
    }

    /**
     * 查询专属里程订单逾期未还排期
     *
     * @param params orderCode
     *               订单号-long
     *               userIds
     *               用户id(查询C端用户订单排期)-list
     * @return
     * @throws Exception
     */
    @Override
    public Paged<OrderScheduleOverdueDto> getExclusivelOrderOverdue(Map<String, Object> params, int pageNum,
                                                                    int pageSize) throws Exception {
        return getOverdue(params, OrderTypeEnum.EXCLUSIVEL, pageNum, pageSize);
    }

    /**
     * 是否存在逾期未还订单
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    public Boolean getIsOverdue(Long orderCode) {
        return orderScheduleMapper.getOverdueCount(orderCode, OrderScheduleStatusEnum.NO.getValue()) > 0 ? true : false;
    }

    /**
     * 查询经销商订单本期排期
     *
     * @param params orderCode 订单号-long
     *               dealerIds 经销商id(查询经销商订单排期)-list
     * @return
     * @throws Exception
     */
    @Override
    public Paged<OrderScheduleCurrentPeriodDto> getDealerOrderCurrentPeriod(Map<String, Object> params, int pageNum,
                                                                            int pageSize) throws Exception {
        return getCurrentPeriod(params, OrderTypeEnum.DEALER, pageNum, pageSize);
    }

    /**
     * 查询经销商订单逾期未还排期
     *
     * @param params orderCode 订单号-long
     *               dealerIds 经销商id(查询经销商订单排期)-list
     * @return
     * @throws Exception
     */
    @Override
    public Paged<OrderScheduleOverdueDto> getDealerOrderOverdue(Map<String, Object> params, int pageNum, int pageSize)
            throws Exception {
        return getOverdue(params, OrderTypeEnum.DEALER, pageNum, pageSize);
    }

    /**
     * 查询本期排期
     *
     * @param params    orderCode：订单号-long <br/>
     *                  userIds：用户id(查询C端用户订单排期)-list <br/>
     *                  dealerIds：经销商id(查询经销商订单排期)-list
     * @param orderType 订单类型枚举-enum
     * @param pageNum   页数
     * @param pageSize  每页条数
     * @return
     * @throws Exception
     */
    @Override
    public Paged<OrderScheduleCurrentPeriodDto> getCurrentPeriod(Map<String, Object> params, OrderTypeEnum orderType,
                                                                 int pageNum, int pageSize) throws Exception {
        params = checkOrderType(params, orderType);

        long total = orderScheduleMapper.getCurrentPeriodPageCount(params);
        if (total <= 0) {
            return new Paged<>(null, total, pageSize);
        }
        List<OrderScheduleBean> page = orderScheduleMapper.getCurrentPeriodPage(params, pageNum, pageSize);

        List<OrderScheduleCurrentPeriodDto> beanDtoList = null;
        if (page != null && page.size() > 0) {
            beanDtoList = new ArrayList<>();
            for (OrderScheduleBean orderScheduleBean : page) {
                OrderScheduleCurrentPeriodDto beanDto = Convert.toOrderScheduleCurrentPeriodBeanDto(orderScheduleBean);
                // 统计数据
                OrderScheduleStatisticsDto orderScheduleStatisticsDto = getScheduleStatistics(
                        orderScheduleBean.getOrderCode());
                // 经销商需要加上保证金
                if (OrderTypeEnum.DEALER.equals(orderType)) {
                    // 已还期数总金额
                    beanDto.setHasPayAmount(orderScheduleStatisticsDto.getHasPayAmount()
                            .add(orderScheduleStatisticsDto.getHasPayDeposit()));
                    // 总金额
                    beanDto.setTotalAmount(orderScheduleStatisticsDto.getTotalAmount()
                            .add(orderScheduleStatisticsDto.getTotalDeposit()));
                } else {
                    // 已还期数总金额
                    beanDto.setHasPayAmount(orderScheduleStatisticsDto.getHasPayAmount());
                    // 总金额
                    beanDto.setTotalAmount(orderScheduleStatisticsDto.getTotalAmount());
                }

                // 逾期次数（包括逾期已还）
                beanDto.setOverduePeriods(orderScheduleStatisticsDto.getOverduePeriods());

                beanDtoList.add(beanDto);
            }
        }

        return new Paged<>(beanDtoList, total, pageSize);
    }

    /**
     * 查询逾期未还排期
     *
     * @param params    orderCode：订单号-long <br/>
     *                  userIds：用户id(查询C端用户订单排期)-list <br/>
     *                  dealerIds：经销商id(查询经销商订单排期)-list
     * @param orderType 订单类型枚举-enum
     * @param pageNum   页数
     * @param pageSize  每页条数
     * @return
     * @throws Exception
     */
    @Override
    public Paged<OrderScheduleOverdueDto> getOverdue(Map<String, Object> params, OrderTypeEnum orderType, int pageNum,
                                                     int pageSize) throws Exception {
        params = checkOrderType(params, orderType);

        long total = orderScheduleMapper.getOverduePageCount(params);
        if (total <= 0) {
            return new Paged<>(null, total, pageSize);
        }
        List<OrderScheduleBean> page = orderScheduleMapper.getOverduePage(params, pageNum, pageSize);

        List<OrderScheduleOverdueDto> beanDtoList = null;
        if (page != null && page.size() > 0) {
            beanDtoList = new ArrayList<>();
            for (OrderScheduleBean orderScheduleBean : page) {
                OrderScheduleOverdueDto beanDto = Convert.toOrderScheduleOverdueBeanDto(orderScheduleBean);
                // 统计数据
                OrderScheduleStatisticsDto orderScheduleStatisticsDto = getScheduleStatistics(
                        orderScheduleBean.getOrderCode());
                // 经销商需要加上保证金
                if (OrderTypeEnum.DEALER.equals(orderType)) {
                    // 已还期数总金额
                    beanDto.setHasPayAmount(orderScheduleStatisticsDto.getHasPayAmount()
                            .add(orderScheduleStatisticsDto.getHasPayDeposit()));
                    // 总金额
                    beanDto.setTotalAmount(orderScheduleStatisticsDto.getTotalAmount()
                            .add(orderScheduleStatisticsDto.getTotalDeposit()));
                } else {
                    // 已还期数总金额
                    beanDto.setHasPayAmount(orderScheduleStatisticsDto.getHasPayAmount());
                    // 总金额
                    beanDto.setTotalAmount(orderScheduleStatisticsDto.getTotalAmount());
                }

                // 逾期未付次数
                beanDto.setOverdueNoPayPeriods(orderScheduleStatisticsDto.getOverdueNoPayPeriods());
                // 逾期次数（包括逾期已还）
                beanDto.setOverduePeriods(orderScheduleStatisticsDto.getOverduePeriods());
                // 计算逾期天数
                int daysDiff = (int) DateUtil.getDaysDiff(orderScheduleBean.getPayableDate(), LocalDate.now());
                beanDto.setOverdueDays(daysDiff < 0 ? 0 : daysDiff);

                beanDtoList.add(beanDto);
            }
        }
        return new Paged<>(beanDtoList, total, pageSize);
    }

    /**
     * 获取逾期订单总数
     *
     * @param orderType 订单类型
     * @return
     */
    @Override
    public int getOverdueTotal(OrderTypeEnum orderType) throws Exception {
        Map<String, Object> params = new HashMap<>();
        params = checkOrderType(params, orderType);
        return (int) orderScheduleMapper.getOverduePageCount(params);
    }

    /**
     * 检验参数订单类型
     *
     * @param params 查询参数
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> checkOrderType(Map<String, Object> params, OrderTypeEnum orderType) throws Exception {
        params.put("nowDate", LocalDate.now());
        if (orderType == null) {
            // Exception
            throw new BizException(OrderExceptionCodeEnum.NOT_EMPTY.getCode(), "订单类型不能为空");
        } else if (OrderTypeEnum.DEALER.equals(orderType)) {
            params.put("isDealer", true);
            // 经销商订单
            List<Long> dealerIds = ObjectCastUtil.castList(params.get("dealerIds"));
            if (dealerIds != null && dealerIds.size() > 0) {
                params.put("dealerIds", dealerIds);
            } else {
                params.remove("dealerIds");
            }
        } else if (OrderTypeEnum.EXCLUSIVEL.equals(orderType)) {
            params.put("isUser", true);
            // C端用户专属里程订单
            List<Long> userIds = ObjectCastUtil.castList(params.get("userIds"));
            if (userIds != null && userIds.size() > 0) {
                params.put("userIds", userIds);
            } else {
                params.remove("userIds");
            }
        } else {
            throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "订单类型错误");
        }
        return params;
    }

    /**
     * 统计排期信息
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    public OrderScheduleStatisticsDto getScheduleStatistics(Long orderCode) {
        OrderScheduleStatisticsDto result = new OrderScheduleStatisticsDto();
        List<OrderScheduleBean> list = orderScheduleMapper.getList(orderCode, null);
        if (list != null && list.size() > 0) {
            for (OrderScheduleBean orderScheduleBean : list) {
                // 总金额
                result.setTotalAmount(result.getTotalAmount().add(orderScheduleBean.getPayable()));
                // 保证金总金额
                result.setTotalDeposit(result.getTotalDeposit().add(orderScheduleBean.getDeposit()));
                if (OrderScheduleStatusEnum.ALREADY.getValue() == orderScheduleBean.getStatus()) {
                    // 已还期数
                    result.setHasPayPeriods(result.getHasPayPeriods() + 1);
                    // 已还款金额
                    result.setHasPayAmount(result.getHasPayAmount().add(orderScheduleBean.getPayable()));
                    // 已还保证金金额
                    result.setHasPayDeposit(result.getHasPayDeposit().add(orderScheduleBean.getDeposit()));
                    //第一期不计算
                    if (orderScheduleBean.getPeriods() != 1) {
                        if (DateUtil.getDaysDiff(orderScheduleBean.getPayableDate(),
                                LocalDate.from(orderScheduleBean.getPaySuccessTime())) > 0) {
                            // 实际支付日期大于应支付日期
                            result.setOverduePeriods(result.getOverduePeriods() + 1);
                        }
                    }
                } else {
                    // 未还款
                    if (orderScheduleBean.getPayableDate() == null) {
                        // 未还期数
                        result.setWaitPayPeriods(result.getWaitPayPeriods() + 1);
                        result.setWaitPayAmount(result.getWaitPayAmount().add(orderScheduleBean.getPayable()));
                        // 未还金额
                    } else if (DateUtil.getDaysDiff(orderScheduleBean.getPayableDate(), LocalDate.now()) > 0) {
                        // 当前日期大于应支付日期
                        result.setOverduePeriods(result.getOverduePeriods() + 1);
                        result.setOverdueNoPayPeriods(result.getOverdueNoPayPeriods() + 1);
                    }
                }
            }
        }
        return result;
    }

    /**
     * 新增用户排期信息
     *
     * @param createDto
     * @return true：成功，false：失败
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean createUserOrderSchedule(OrderScheduleUserCreateDto createDto) {
        List<OrderScheduleBean> orderScheduleBeans = OrderUtil.generateOrderSchedule(createDto);
        // 批量新增
        int rst = orderScheduleMapper.createBatch(orderScheduleBeans);
        if (rst < createDto.getTotalPeriods()) {
            throw new BizException("订单(" + createDto.getOrderCode() + ")新增用户排期信息失败！");
        }

        return true;
    }

    /**
     * 新增经销商排期信息
     *
     * @param createDto
     * @return true：成功，false：失败
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean createDealerOrderSchedule(OrderScheduleDealerCreateDto createDto) {
        // 计算应付款金额(总租金除以总期数)
        BigDecimal payable = createDto.getRent().divide(new BigDecimal(createDto.getTotalPeriods()), 2, BigDecimal.ROUND_DOWN);
        BigDecimal money = new BigDecimal("0");
        List<OrderScheduleBean> orderScheduleList = new ArrayList<>();
        for (int i = 1; i <= createDto.getTotalPeriods(); i++) {
            OrderScheduleBean orderSchedule = new OrderScheduleBean();
            // 订单号
            orderSchedule.setOrderCode(createDto.getOrderCode());
            // 排期期数
            orderSchedule.setPeriods(i);
            // 总还款期数
            orderSchedule.setTotalPeriods(createDto.getTotalPeriods());
            // 最后一期用总金额减去除最后一期的总金额
            if (i == createDto.getTotalPeriods()) {
                orderSchedule.setPayable(createDto.getRent().subtract(money));
            } else {
                money = money.add(payable);
                // 应付款金额（不含保证金）
                orderSchedule.setPayable(payable);
            }
            if (i == 1) {
                // 保证金
                orderSchedule.setDeposit(createDto.getDeposit());
            } else {
                // 保证金
                orderSchedule.setDeposit(BigDecimal.ZERO);

                // 应还款日
                orderSchedule.setPayableDate(LocalDate.
                        of(createDto.getStartLeaseDate().getYear(),
                                createDto.getStartLeaseDate().getMonth(),
                                createDto.getRepayDate())
                        .plus((i - 1) * createDto.getPaymentCycle(), ChronoUnit.MONTHS));
            }
            // 经销商id
            orderSchedule.setDealerId(createDto.getDealerId());
            // 状态（0：未还款，1：已还款，2：已终止）
            orderSchedule.setStatus(OrderScheduleStatusEnum.NO.getValue());

            orderScheduleList.add(orderSchedule);
        }

        int rst = orderScheduleMapper.createBatch(orderScheduleList);

        return rst > 0 ? true : false;
    }

    /**
     * 根据还款计划id查询还款信息
     *
     * @param ids 还款计划id
     * @return
     */
    @Override
    public List<OrderScheduleDto> getOrderScheduleDtoListById(List<Integer> ids) {
        List<OrderScheduleBean> orderScheduleBeanList = null;
        if (ids != null && ids.size() > 0) {
            orderScheduleBeanList = orderScheduleMapper.getListByIds(ids);
        }

        return Convert.toOrderScheduleBeanDto(orderScheduleBeanList);
    }

    @Override
    public List<OrderScheduleUnpaidDto> getOrderScheduleUnpaidByDealerId(Integer dealerId) {

        return orderScheduleMapper.getOrderScheduleUnpaidByDealerId(dealerId);
    }

    @Override
    public List<OrderScheduleRelationDto> getOrderScheduleRelationDto(Long orderCode) {

        List<OrderScheduleBean> beanList = orderScheduleMapper.getOrderScheduleRelationDto(orderCode);
        return Convert.toOrderScheduleRelationDto(beanList);
    }


    /**
     * 根据还款计划id查询经销商订单还款信息
     *
     * @param ids 还款计划id
     * @return
     */
    @Override
    public List<OrderScheduleDto> getOrderDealerListByIds(List<Integer> ids) {
        List<OrderScheduleBean> orderScheduleBeanList = null;
        if (ids != null && ids.size() > 0) {
            orderScheduleBeanList = orderScheduleMapper.getOrderDealerListByIds(ids);
        }

        return Convert.toOrderScheduleBeanDto(orderScheduleBeanList);
    }

    @Override
    public BigDecimal getDownPaymentByOrderCode(Long orderCode) {
        return orderScheduleMapper.getDownPaymentByOrderCode(orderCode);
    }

    @Override
    public BigDecimal getAmountPaidByOrderCode(Long orderCode, Integer status) {
        return orderScheduleMapper.getAmountPaidByOrderCode(orderCode, status);
    }

    /**
     * 还款成功修改排期信息
     *
     * @param modifyDto
     * @return
     * @throws BizException
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyOrderScheduleRepayment(OrderScheduleRepaymentModifyDto modifyDto) throws BizException {
        Boolean result = false;
        OrderScheduleBean orderSchedule = Convert.toOrderScheduleBean(modifyDto);

        if (orderScheduleMapper.modifyOrderScheduleRepayment(orderSchedule) > 0) {
            result = true;
        }
        return result;
    }

    /**
     * 修改经销商订单排期应付款日期
     *
     * @param modifyDto
     * @return
     * @throws BizException
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyDealerOrderSchedulePayableDate(OrderSchedulePayableDateModifyDto modifyDto)
            throws BizException {
        Boolean result = false;
        OrderScheduleBean orderSchedule = Convert.toOrderScheduleBean(modifyDto);
        if (orderScheduleMapper.modifyDealerOrderSchedulePayableDate(orderSchedule) > 0) {
            result = true;
        }
        return result;
    }

    /**
     * 修改经销商订单排期应付款日期
     *
     * @param modifyDtoList
     * @return
     * @throws BizException
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyDealerOrderSchedulePayableDate(List<OrderSchedulePayableDateModifyDto> modifyDtoList)
            throws BizException {
        Boolean result = true;
        int ret = 0;

        for (OrderSchedulePayableDateModifyDto orderSchedulePayableDateModifyDto : modifyDtoList) {
            if (modifyDealerOrderSchedulePayableDate(orderSchedulePayableDateModifyDto)) {
                ret += 1;
            }
        }
        if (ret < modifyDtoList.size()) {
            logger.error(
                    "[modifyDealerOrderSchedulePayableDate]修改经销商订单排期应付款日期失败:" + JSONObject.toJSONString(modifyDtoList));
            throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(), "修改失败");
        }

        return result;
    }

    @Override
    public Integer getOrderScheduleCurrentPeriodCount(Integer dealerId) {
        Integer count = orderScheduleMapper.getOrderScheduleCurrentPeriodCount(dealerId);
        return count == null ? 0 : count;
    }

    @Override
    public Integer getOrderScheduleOverdueCount(Integer dealerId) {
        Integer count = orderScheduleMapper.getOrderScheduleOverdueCount(dealerId);
        return count == null ? 0 : count;
    }

    @Override
    public BigDecimal getDealerFirstPayable(Long orderCode) {
        return orderScheduleMapper.getDealerFirstPayable(orderCode);
    }

    @Override
    public BigDecimal getDealerPayable(Long orderCode) {
        return orderScheduleMapper.getDealerPayable(orderCode);
    }

    /**
     * 查询订单排期信息
     *
     * @param orderCode 订单号
     * @param periods   期数
     * @return
     */
    @Override
    public OrderScheduleDto getOrderScheduleByPeriods(Long orderCode, Integer periods) {
        return Convert.toOrderScheduleBeanDto(orderScheduleMapper.getOrderScheduleByPeriods(orderCode, periods));
    }

    /**
     * 支付完成修改排期信息
     *
     * @param modifyDto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyPay(OrderPayModifyDto modifyDto) {
        if (orderScheduleMapper.modifyPay(Convert.toOrderScheduleBean(modifyDto),
                OrderScheduleStatusEnum.NO.getValue()) > 0) {
            return true;
        }
        return false;
    }

    @Override
    public Integer getDealerByDealerId(Integer dealerId) {
        return orderScheduleMapper.getDealerByDealerId(dealerId);
    }

    /**
     * 根据id修改排期状态
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public int modifyStatusByIdAndOrderCode(Integer id, Integer status, Integer payWay) {
        return orderScheduleMapper.modifyStatusByIdAndOrderCode(id, status, payWay);
    }

    /**
     * 逾期未还订单数量
     *
     * @return
     */
    @Override
    public Integer getOrderOverdue() {
        return orderScheduleMapper.getOrderOverdue();
    }

    /**
     * 专属订单未还排期
     *
     * @param payableDate
     * @return
     */
    @Override
    public List<OrderScheduleDto> getExclusivelUnpayPeriod(LocalDate payableDate, boolean isAll) {
        return Convert.toOrderScheduleBeanDto(
                orderScheduleMapper.getExclusivelUnpayPeriod(payableDate, OrderScheduleStatusEnum.NO.getValue(),
                        isAll));
    }

    /**
     * 专属订单未还排期
     *
     * @param payableDate
     * @param isAll       true:查询<payableDate，false：查询=payableDate
     * @return
     */
    @Override
    public List<OrderScheduleDto> getDealerUnpayPeriod(LocalDate payableDate, boolean isAll) {
        return Convert.toOrderScheduleBeanDto(
                orderScheduleMapper.getDealerUnpayPeriod(payableDate, OrderScheduleStatusEnum.NO.getValue(), isAll));
    }

    /**
     * 排期修改为已终止
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public boolean modifyCancel(Long orderCode) {
        orderScheduleMapper.modifyCancel(orderCode, OrderScheduleStatusEnum.TERMINATION.getValue(), null);
        return true;
    }

    /**
     * 排期修改为已终止
     *
     * @param orderCode           订单号
     * @param orderScheduleStatus 取消前状态
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public boolean modifyCancel(Long orderCode, OrderScheduleStatusEnum orderScheduleStatus) {
        orderScheduleMapper.modifyCancel(orderCode, OrderScheduleStatusEnum.TERMINATION.getValue(),
                orderScheduleStatus.getValue());
        return true;
    }

    /**
     * 查询专属里程本期还款计划导出数据
     *
     * @param selectParams
     * @return
     */
    @Override
    public List<OrderScheduleCurrentPeriodDto> getExclusivelOrderCurrentPeriodDownload(
            Map<String, Object> selectParams) {
        if (selectParams == null) {
            selectParams = new HashMap<>(0);
        }
        List<OrderScheduleCurrentPeriodDto> result = orderScheduleMapper
                .getExclusivelOrderCurrentPeriodDownload(selectParams);

        return result;
    }

    /**
     * 查询专属里程本期还款计划导出数据条数
     *
     * @param selectParams
     * @return
     */
    @Override
    public Long getExclusivelOrderCurrentPeriodDownloadCount(Map<String, Object> selectParams) {
        if (selectParams == null) {
            selectParams = new HashMap<>(0);
        }
        Long result = orderScheduleMapper
                .getExclusivelOrderCurrentPeriodDownloadCount(selectParams);

        return result;
    }

    /**
     * 查询专属里程逾期数据导出数据
     *
     * @param selectParams
     * @return
     */
    @Override
    public List<OrderScheduleOverdueDto> getExclusivelOrderOverdueDownload(Map<String, Object> selectParams) {
        if (selectParams == null) {
            selectParams = new HashMap<>(0);
        }
        List<OrderScheduleOverdueDto> result = orderScheduleMapper
                .getExclusivelOrderOverdueDownload(selectParams);

        if (result != null) {
            for (OrderScheduleOverdueDto orderScheduleOverdueDto : result) {
                // 计算逾期天数
                orderScheduleOverdueDto.setOverdueDays(
                        (int) DateUtil.getDaysDiff(orderScheduleOverdueDto.getPayableDate(), LocalDate.now()));

            }
        }

        return result;
    }

    /**
     * 查询专属里程逾期数据导出数据条数
     *
     * @param selectParams
     * @return
     */
    @Override
    public Long getExclusivelOrderOverdueDownloadCount(Map<String, Object> selectParams) {
        if (selectParams == null) {
            selectParams = new HashMap<>(0);
        }
        Long result = orderScheduleMapper.getExclusivelOrderOverdueDownloadCount(selectParams);

        return result;
    }

    /**
     * 查询应还日期小于查询日期的有效排期信息(未还、已还)
     *
     * @param userId      用户id
     * @param payableDate 查询日期
     * @return
     */
    @Override
    public List<OrderScheduleDto> getOrderScheduleLtDate(Integer userId, LocalDate payableDate) {
        return Convert.toOrderScheduleBeanDto(orderScheduleMapper.getOrderScheduleLtDate(userId, payableDate,
                Arrays.asList(OrderScheduleStatusEnum.NO.getValue(), OrderScheduleStatusEnum.ALREADY.getValue())));
    }

    /**
     * 查询排期信息
     *
     * @param scheduleIds 排期ids
     * @return
     */
    @Override
    public Map<Integer, OrderScheduleDto> getOrderSchedule(List<Integer> scheduleIds) {
        List<OrderScheduleBean> scheduleBeans = orderScheduleMapper.getListByIds(scheduleIds);
        if (scheduleBeans == null) {
            return null;
        }
        return scheduleBeans.stream()
                .collect(Collectors.toMap(OrderScheduleBean::getId, bean -> Convert.toOrderScheduleBeanDto(bean)));
    }

}
